package com.syx.judge.Service.Impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.syx.api.Model.DTO.JudgeSubmitDTO;
import com.syx.api.Model.UserExeResult;
import com.syx.api.Model.VO.UserQuestionResultVO;
import com.syx.commoncore.Constant.Constant;
import com.syx.commoncore.Constant.JudgeConstants;
import com.syx.commoncore.Model.Result;
import com.syx.commoncore.enums.CodeRunStatus;
import com.syx.judge.Mapper.UserSubmitMapper;
import com.syx.judge.Model.SandBoxExecuteResult;
import com.syx.judge.Model.UserSubmit;
import com.syx.judge.Service.IJudgeService;
import com.syx.judge.Service.ISandBoxService;
import com.syx.judge.Service.ISandboxPoolService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

//只判断结果对不对，代码沙箱
@Service
public class IJudgeServiceImpl implements IJudgeService {

    @Resource
    ISandBoxService iSandBoxService;

    @Resource
    UserSubmitMapper userSubmitMapper;

    @Resource
    ISandboxPoolService iSandboxPoolService;



    @Override
    public Result<UserQuestionResultVO> doJudgeJavaCode(JudgeSubmitDTO judgeSubmitDTO) {
        //传入数据的代码和输入的测试用例交给沙箱进行操作，沙箱操作成功后返回数据
        SandBoxExecuteResult sandBoxExecuteResult=
                iSandboxPoolService.exeJavaCode(judgeSubmitDTO.getUserId(), judgeSubmitDTO.getUserCode(),judgeSubmitDTO.getInputList());
        //成功的情况,给用户返回的
        UserQuestionResultVO userQuestionResultVO=new UserQuestionResultVO();
        //执行没问题但是并不代表过用例
        if (sandBoxExecuteResult!=null && CodeRunStatus.SUCCEED.equals(sandBoxExecuteResult.getRunStatus())){
            //判断是否过测试用例
            userQuestionResultVO = doJudge(judgeSubmitDTO, sandBoxExecuteResult, userQuestionResultVO);

            //成功
        }else {
            //返回结果为空,或者出现异常
            //失败
            userQuestionResultVO.setPass(Constant.FALSE);
            //沙箱返回不为空，但是constantCode不是正确的
            if (sandBoxExecuteResult!=null){
                userQuestionResultVO.setExeMessage(sandBoxExecuteResult.getExeMessage());
            }
            else {
                //有可能出现异常情况
                userQuestionResultVO.setExeMessage(CodeRunStatus.UNKNOWN_FAILED.getMsg());

            }
            //0分
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
        }
        //提交用户最新代码并且覆盖掉上一次代码
        saveUserSubmit(judgeSubmitDTO, userQuestionResultVO);
        return Result.success(userQuestionResultVO);


    }

    private UserQuestionResultVO doJudge(JudgeSubmitDTO judgeSubmitDTO, SandBoxExecuteResult sandBoxExecuteResult, UserQuestionResultVO userQuestionResultVO) {
        //比对执行结果和时间限制和空间限制
        //沙箱中输出结果
        List<String> sandBoxExecuteOutputList = sandBoxExecuteResult.getOutputList();
        List<String> judgeOutputList = judgeSubmitDTO.getOutputList();
        if (sandBoxExecuteOutputList.size()!=judgeOutputList.size()){
            //个数都不对
            userQuestionResultVO.setPass(Constant.FALSE);
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.FAILED.getMsg());
            return userQuestionResultVO;

        }
            //数量相等
        List<UserExeResult> userExeResultList=new ArrayList<>();
        //比对判题逻辑是否通过
        boolean passed = resultCompare(judgeSubmitDTO, judgeOutputList, sandBoxExecuteOutputList, userExeResultList);
        //比对结果完全比对的上，比对空间限制
        if (sandBoxExecuteResult.getUseMemory()> judgeSubmitDTO.getSpaceLimit()){
                    userQuestionResultVO.setPass(Constant.FALSE);
                    userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
                    //超出空间限制
                    userQuestionResultVO.setExeMessage(CodeRunStatus.OUT_OF_MEMORY.getMsg());
                    return userQuestionResultVO;
        }
        if (sandBoxExecuteResult.getUseTime()> judgeSubmitDTO.getTimeLimit()){
                    userQuestionResultVO.setPass(Constant.FALSE);
                    userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
                    //超出空间限制
                    userQuestionResultVO.setExeMessage(CodeRunStatus.OUT_OF_TIME.getMsg());
                    return userQuestionResultVO;
        }
                //判题成功
        userQuestionResultVO.setPass(Constant.TRUE);
                //计算默认得分
        int score= (judgeSubmitDTO.getDifficulty()+1)*JudgeConstants.DEFAULT_SCORE;
        userQuestionResultVO.setScore(score);
        userQuestionResultVO.setUserExeResultList(userExeResultList);
        if (!passed){
                userQuestionResultVO.setPass(Constant.FALSE);
                userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
                userQuestionResultVO.setExeMessage(CodeRunStatus.NOT_ALL_PASSED.getMsg());
                return userQuestionResultVO;

            }
        return userQuestionResultVO;



    }

    private static boolean resultCompare(JudgeSubmitDTO judgeSubmitDTO, List<String> judgeOutputList, List<String> sandBoxExecuteOutputList, List<UserExeResult> userExeResultList) {
        boolean passed=true;
        for (int i = 0; i < judgeOutputList.size(); i++) {
            String sandBoxExecuteOutputListComparison = sandBoxExecuteOutputList.get(i);
            String judgeOutputListComparison = judgeOutputList.get(i);
            String input = judgeSubmitDTO.getInputList().get(i);
            //返回给用户的列表
            UserExeResult userExeResult=new UserExeResult();
            userExeResult.setInput(input);
            //用户输出结果
            userExeResult.setOutput(judgeOutputListComparison);
            //实际输出结果
            userExeResult.setExeOutput(sandBoxExecuteOutputListComparison);

            userExeResultList.add(userExeResult);
            //判断结果是否相等
            if (!sandBoxExecuteOutputListComparison.equals(judgeOutputListComparison)){
                passed=false;

            }

        }
        return passed;
    }

    private void saveUserSubmit(JudgeSubmitDTO judgeSubmitDTO, UserQuestionResultVO userQuestionResultVO) {
        UserSubmit userSubmit=new UserSubmit();
        BeanUtil.copyProperties(userQuestionResultVO,userSubmit);
        userSubmit.setUserId(judgeSubmitDTO.getUserId());
        userSubmit.setQuestionId(judgeSubmitDTO.getQuestionId());
        userSubmit.setExamId(judgeSubmitDTO.getExamId());
        userSubmit.setProgramType(judgeSubmitDTO.getProgramType());
        userSubmit.setUserCode(judgeSubmitDTO.getUserCode());
        userSubmit.setCreateBy(judgeSubmitDTO.getUserId());
        userSubmit.setCaseJudgeRes(JSON.toJSONString(userQuestionResultVO.getUserExeResultList()));
        userSubmitMapper.delete(new LambdaQueryWrapper<UserSubmit>()
                .eq(UserSubmit::getUserId, judgeSubmitDTO.getUserId())
                .eq(UserSubmit::getQuestionId, judgeSubmitDTO.getQuestionId())
                .isNull(judgeSubmitDTO.getExamId()==null,UserSubmit::getExamId)
                .eq(judgeSubmitDTO.getExamId()!=null,UserSubmit::getExamId, judgeSubmitDTO.getExamId())
        );
        userSubmitMapper.insert(userSubmit);
    }


}
